#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
推荐系统模块 (Recommendation System Module) - 为 Ali Bao Bao 电商系统提供智能推荐功能 (Provides intelligent recommendations for the Ali Bao Bao e-commerce system)
包含协同过滤、内容推荐和混合推荐算法 (Includes collaborative filtering, content-based, and hybrid algorithms)
"""

import json
import math
import random
from typing import Dict, List, Optional, Tuple
from datetime import datetime, timedelta
from collections import defaultdict, Counter
import os

from product import Product
from recommendation_algorithms import CollaborativeFiltering, ContentBasedFiltering, PopularityBasedFiltering


class UserBehaviorTracker:
    """用户行为追踪器 (User Behavior Tracker) - 记录和分析用户行为数据 (Records and analyzes user behavior data)"""
    
    def __init__(self, behavior_file="user_behaviors.json"):
        self.behavior_file = behavior_file
        self.behaviors = self._load_behaviors()
    
    def _load_behaviors(self) -> Dict:
        """加载用户行为数据 (Load user behavior data)"""
        try:
            with open(self.behavior_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except (FileNotFoundError, json.JSONDecodeError):
            return {
                "views": {},      # 用户浏览记录
                "searches": {},   # 用户搜索记录
                "purchases": {},  # 用户购买记录
                "ratings": {},    # 用户评分记录
                "cart_adds": {}   # 购物车添加记录
            }
    
    def _save_behaviors(self):
        """保存用户行为数据 (Save user behavior data)"""
        with open(self.behavior_file, 'w', encoding='utf-8') as f:
            json.dump(self.behaviors, f, ensure_ascii=False, indent=2)
    
    def record_view(self, user_id: str, product_id: str, timestamp: str = None):
        """记录用户浏览行为 (Record user view behavior)"""
        if timestamp is None:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        if user_id not in self.behaviors["views"]:
            self.behaviors["views"][user_id] = []
        
        # 避免重复记录相同商品的浏览
        existing_view = next((v for v in self.behaviors["views"][user_id] 
                            if v["product_id"] == product_id and 
                            abs((datetime.strptime(v["timestamp"], "%Y-%m-%d %H:%M:%S") - 
                                 datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")).total_seconds()) < 300), None)
        
        if not existing_view:
            self.behaviors["views"][user_id].append({
                "product_id": product_id,
                "timestamp": timestamp
            })
            # 只保留最近100次浏览记录
            if len(self.behaviors["views"][user_id]) > 100:
                self.behaviors["views"][user_id] = self.behaviors["views"][user_id][-100:]
            self._save_behaviors()
    
    def record_search(self, user_id: str, keyword: str, results_count: int, timestamp: str = None):
        """记录用户搜索行为 (Record user search behavior)"""
        if timestamp is None:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        if user_id not in self.behaviors["searches"]:
            self.behaviors["searches"][user_id] = []
        
        self.behaviors["searches"][user_id].append({
            "keyword": keyword,
            "results_count": results_count,
            "timestamp": timestamp
        })
        # 只保留最近50次搜索记录
        if len(self.behaviors["searches"][user_id]) > 50:
            self.behaviors["searches"][user_id] = self.behaviors["searches"][user_id][-50:]
        self._save_behaviors()
    
    def record_purchase(self, user_id: str, product_id: str, quantity: int = 1, timestamp: str = None):
        """记录用户购买行为 (Record user purchase behavior)"""
        if timestamp is None:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        if user_id not in self.behaviors["purchases"]:
            self.behaviors["purchases"][user_id] = []
        
        self.behaviors["purchases"][user_id].append({
            "product_id": product_id,
            "quantity": quantity,
            "timestamp": timestamp
        })
        self._save_behaviors()
    
    def record_rating(self, user_id: str, product_id: str, rating: float, timestamp: str = None):
        """记录用户评分行为 (Record user rating behavior)"""
        if timestamp is None:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        if user_id not in self.behaviors["ratings"]:
            self.behaviors["ratings"][user_id] = {}
        
        self.behaviors["ratings"][user_id][product_id] = {
            "rating": rating,
            "timestamp": timestamp
        }
        self._save_behaviors()
    
    def record_cart_add(self, user_id: str, product_id: str, timestamp: str = None):
        """记录用户添加购物车行为 (Record add-to-cart behavior)"""
        if timestamp is None:
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        if user_id not in self.behaviors["cart_adds"]:
            self.behaviors["cart_adds"][user_id] = []
        
        # 避免重复记录
        existing_add = next((a for a in self.behaviors["cart_adds"][user_id] 
                            if a["product_id"] == product_id and 
                            abs((datetime.strptime(a["timestamp"], "%Y-%m-%d %H:%M:%S") - 
                                 datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")).total_seconds()) < 300), None)
        
        if not existing_add:
            self.behaviors["cart_adds"][user_id].append({
                "product_id": product_id,
                "timestamp": timestamp
            })
            # 只保留最近50次添加记录
            if len(self.behaviors["cart_adds"][user_id]) > 50:
                self.behaviors["cart_adds"][user_id] = self.behaviors["cart_adds"][user_id][-50:]
            self._save_behaviors()
    
    def get_user_preferences(self, user_id: str) -> Dict:
        """获取用户偏好分析 (Get user preference analysis)"""
        preferences = {
            "categories": Counter(),
            "price_range": {"min": float('inf'), "max": 0},
            "provinces": Counter(),
            "viewed_products": set(),
            "purchased_products": set(),
            "rated_products": {}
        }
        
        # 分析浏览记录
        if user_id in self.behaviors["views"]:
            for view in self.behaviors["views"][user_id]:
                product = Product.from_id(view["product_id"])
                if product:
                    preferences["categories"][product.kind] += 1
                    preferences["provinces"][product.province] += 1
                    preferences["price_range"]["min"] = min(preferences["price_range"]["min"], product.prize)
                    preferences["price_range"]["max"] = max(preferences["price_range"]["max"], product.prize)
                    preferences["viewed_products"].add(product.id)
        
        # 分析购买记录
        if user_id in self.behaviors["purchases"]:
            for purchase in self.behaviors["purchases"][user_id]:
                preferences["purchased_products"].add(purchase["product_id"])
        
        # 分析评分记录
        if user_id in self.behaviors["ratings"]:
            preferences["rated_products"] = self.behaviors["ratings"][user_id]
        
        return preferences


# 算法类已移至 recommendation_algorithms.py


class HybridRecommendationSystem:
    """混合推荐系统 (Hybrid Recommendation System) - 结合多种推荐算法 (Combines multiple algorithms)"""
    
    def __init__(self):
        self.behavior_tracker = UserBehaviorTracker()
        self.collaborative_filter = CollaborativeFiltering(self.behavior_tracker)
        self.content_filter = ContentBasedFiltering(self.behavior_tracker)
        self.popularity_filter = PopularityBasedFiltering(self.behavior_tracker)
    
    def get_recommendations(self, user_id: str, num_recommendations: int = 10, 
                          algorithm: str = "hybrid") -> List[Product]:
        """获取推荐商品 (Get recommended products)"""
        product_ids = []
        
        if algorithm == "collaborative":
            product_ids = self.collaborative_filter.recommend_by_collaborative_filtering(
                user_id, num_recommendations)
        elif algorithm == "content":
            product_ids = self.content_filter.recommend_by_content(
                user_id, num_recommendations)
        elif algorithm == "popularity":
            product_ids = self.popularity_filter.recommend_by_popularity(
                user_id, num_recommendations)
        elif algorithm == "hybrid":
            # 混合推荐：结合多种算法
            collaborative_ids = self.collaborative_filter.recommend_by_collaborative_filtering(
                user_id, num_recommendations // 3)
            content_ids = self.content_filter.recommend_by_content(
                user_id, num_recommendations // 3)
            popularity_ids = self.popularity_filter.recommend_by_popularity(
                user_id, num_recommendations // 3)
            
            # 合并推荐结果，去重
            all_ids = collaborative_ids + content_ids + popularity_ids
            product_ids = list(dict.fromkeys(all_ids))[:num_recommendations]
        
        # 转换为Product对象
        recommendations = []
        for product_id in product_ids:
            product = Product.from_id(product_id)
            if product:
                recommendations.append(product)
        
        return recommendations
    
    def get_personalized_recommendations(self, user_id: str, num_recommendations: int = 10) -> List[Product]:
        """获取个性化推荐（智能选择最佳算法）(Get personalized recommendations - auto-select best algorithm)"""
        preferences = self.behavior_tracker.get_user_preferences(user_id)
        
        # 根据用户行为数据选择最佳算法
        if len(preferences["purchased_products"]) >= 3:
            # 用户有足够购买历史，使用协同过滤
            return self.get_recommendations(user_id, num_recommendations, "collaborative")
        elif len(preferences["viewed_products"]) >= 5:
            # 用户有足够浏览历史，使用内容推荐
            return self.get_recommendations(user_id, num_recommendations, "content")
        else:
            # 新用户或行为数据不足，使用流行度推荐
            return self.get_recommendations(user_id, num_recommendations, "popularity")
    
    def get_category_recommendations(self, user_id: str, category: str, 
                                   num_recommendations: int = 5) -> List[Product]:
        """获取特定类别的推荐 (Get category-specific recommendations)"""
        all_recommendations = self.get_personalized_recommendations(user_id, 20)
        category_recommendations = [p for p in all_recommendations if p.kind == category]
        return category_recommendations[:num_recommendations]
    
    def get_trending_products(self, days: int = 7, num_recommendations: int = 10) -> List[Product]:
        """获取热门商品（基于最近几天的行为）(Get trending products based on recent days)"""
        cutoff_date = datetime.now() - timedelta(days=days)
        trending_scores = defaultdict(float)
        
        # 分析最近的行为数据
        for user_views in self.behavior_tracker.behaviors["views"].values():
            for view in user_views:
                view_date = datetime.strptime(view["timestamp"], "%Y-%m-%d %H:%M:%S")
                if view_date >= cutoff_date:
                    trending_scores[view["product_id"]] += 1.0
        
        for user_purchases in self.behavior_tracker.behaviors["purchases"].values():
            for purchase in user_purchases:
                purchase_date = datetime.strptime(purchase["timestamp"], "%Y-%m-%d %H:%M:%S")
                if purchase_date >= cutoff_date:
                    trending_scores[purchase["product_id"]] += 3.0
        
        # 按分数排序并返回商品
        sorted_trending = sorted(trending_scores.items(), key=lambda x: x[1], reverse=True)
        trending_products = []
        
        for product_id, _ in sorted_trending[:num_recommendations]:
            product = Product.from_id(product_id)
            if product:
                trending_products.append(product)
        
        return trending_products


# 为Product类添加from_id方法
def add_from_id_method():
    """为 Product 类添加 from_id 方法 (Add from_id method to Product class)"""
    @classmethod
    def from_id(cls, product_id: str):
        """通过ID获取商品 (Get product by ID)"""
        products = cls._load_all_products()
        for p in products:
            if p.id == product_id:
                return p
        return None
    
    # 动态添加方法到Product类
    Product.from_id = from_id


# 初始化时添加from_id方法
add_from_id_method()


# 全局推荐系统实例
recommendation_system = HybridRecommendationSystem()
